}
static gboolean
-should_map_as_subsurface (GdkWindow *window)
+should_map_as_popup (GdkWindow *window)
{
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
- if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_SUBSURFACE)
- return TRUE;
+ /* Ideally, popup would be temp windows with a parent and grab */
+ if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
+ {
+ /* If a temp window has a parent and a grab, we can use a popup */
+ if (impl->transient_for)
+ {
+ if (impl->grab_input_seat)
+ return TRUE;
+ }
+ else
+ g_warning ("Window %p is a temporary window without parent, "
+ "application will not be able to position it on screen.",
+ window);
+ }
+ /* Yet we need to keep the window type hint tests for compatibility */
switch (impl->hint)
{
- case GDK_WINDOW_TYPE_HINT_TOOLTIP:
+ case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
+ case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:
+ case GDK_WINDOW_TYPE_HINT_COMBO:
return TRUE;
case GDK_WINDOW_TYPE_HINT_UTILITY:
- if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_TEMP)
+ if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_TEMP)
return TRUE;
break;
}
static gboolean
-should_map_as_popup (GdkWindow *window)
+should_map_as_subsurface (GdkWindow *window)
{
GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
- switch (impl->hint)
+ if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_SUBSURFACE)
+ return TRUE;
+
+ if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_TEMP)
+ return FALSE;
+
+ /* if we want a popup, we do not want a subsurface */
+ if (should_map_as_popup (window))
+ return FALSE;
+
+ if (impl->transient_for)
{
- case GDK_WINDOW_TYPE_HINT_POPUP_MENU:
- case GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU:
- case GDK_WINDOW_TYPE_HINT_COMBO:
- return TRUE;
+ GdkWindowImplWayland *impl_parent;
- case GDK_WINDOW_TYPE_HINT_UTILITY:
- if (GDK_WINDOW_TYPE (window) != GDK_WINDOW_TEMP)
+ impl_parent = GDK_WINDOW_IMPL_WAYLAND (impl->transient_for->impl);
+ /* subsurface require that the parent is mapped */
+ if (impl_parent->mapped)
return TRUE;
- break;
+ else
+ g_warning ("Couldn't map window %p as susburface because its parent is not mapped.",
+ window);
- default:
- break;
}
return FALSE;
if (impl->transient_for)
gdk_wayland_window_create_subsurface (window);
else
- g_warning ("Couldn't map as window %p as susburface yet because it doesn't have a parent",
+ g_warning ("Couldn't map window %p as susburface yet because it doesn't have a parent",
window);
}
else if (should_map_as_popup (window))
*
* Passing %NULL for @parent unsets the current transient window.
*
+ * On Wayland, this function can also be used to attach a new
+ * #GTK_WINDOW_POPUP to a #GTK_WINDOW_TOPLEVEL parent already mapped
+ * on screen so that the #GTK_WINDOW_POPUP will be created as a
+ * subsurface-based window #GDK_WINDOW_SUBSURFACE which can be
+ * positioned at will relatively to the #GTK_WINDOW_TOPLEVEL surface.
+ *
* On Windows, this function puts the child window on top of the parent,
* much as the window manager would have done on X.
*/
--- /dev/null
+#include <gtk/gtk.h>
+
+static gboolean
+draw_popup (GtkWidget *widget,
+ cairo_t *cr,
+ gpointer data)
+{
+ cairo_set_source_rgb (cr, 1, 0, 0);
+ cairo_paint (cr);
+
+ return FALSE;
+}
+
+static gboolean
+place_popup (GtkWidget *parent,
+ GdkEvent *event,
+ GtkWidget *popup)
+{
+ GdkEventMotion *ev_motion = (GdkEventMotion *) event;
+ gint width, height;
+
+ gtk_window_get_size (GTK_WINDOW (popup), &width, &height);
+ gtk_window_move (GTK_WINDOW (popup),
+ (int) ev_motion->x_root - width / 2,
+ (int) ev_motion->y_root - height / 2);
+
+ return FALSE;
+}
+
+static gboolean
+on_map_event (GtkWidget *parent,
+ GdkEvent *event,
+ gpointer data)
+{
+ GtkWidget *popup;
+
+ popup = gtk_window_new (GTK_WINDOW_POPUP);
+
+ gtk_widget_set_size_request (GTK_WIDGET (popup), 20, 20);
+ gtk_widget_set_app_paintable (GTK_WIDGET (popup), TRUE);
+ gtk_window_set_transient_for (GTK_WINDOW (popup), GTK_WINDOW (parent));
+ g_signal_connect (popup, "draw", G_CALLBACK (draw_popup), NULL);
+ g_signal_connect (parent, "motion-notify-event", G_CALLBACK (place_popup), popup);
+
+ gtk_widget_show (popup);
+
+ return FALSE;
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_widget_set_events (window, GDK_POINTER_MOTION_MASK);
+ g_signal_connect (window, "destroy", gtk_main_quit, NULL);
+ g_signal_connect (window, "map-event", G_CALLBACK (on_map_event), NULL);
+
+ gtk_widget_show (window);
+
+ gtk_main ();
+
+ return 0;
+}